/**
 * @author Mustafa K. Isik
 * requires compilertoys.jar
 */
import toys.base.*;
import toys.compiler.*;

public class MiniLangRDParser implements Parser{

	private TokenStream tokenstream;
	private Token lookahead;

	public Tree parse(Tokenstream t) throws SyntaxError{
		tokenstream = t;
		nextToken();
		return program();
	}

	Tree program() throws SyntaxError{
		Tree result = new Tree("program");

		if(lookahead.equals("print")){
			System.out.println("deriving program -> statements");
			result.child(statements());
		}else{
			throw new SyntaxError("expected print, but got " + lookahead);
		}

		return result;
	}

	Tree statements() throws SyntaxError{
		Tree result = new Tree("statements");

		if(lookahead.equals("print")){
			System.out.println("deriving statements -> statement");
			result.child(statement());
		}else{
			throw new SyntaxError("expected print, but got " + lookahead);
		}

		return result;
	}

	Tree statement() throws SyntaxError{
		Tree result = new Tree("statement");

		if(lookahead.equals("print")){
			System.out.println("deriving statement -> print expression ;");
			result.child(terminal("print"));
			result.child(expression());
			result.child(terminal(";"));
		}else{
			throw new SyntaxError("expected print, but got " + lookahead);
		}

		return result;
	}

	Tree expression() throws SyntaxError{
		Tree result = new Tree("expression");

		if(lookahead.equals("-") || lookahead.equals("(") || lookahead.equals("numeral")){
			System.out.println("deriving expression -> term subexpression");
			result.child(term());
			result.child(subexpression());
		}else{
			throw new SyntaxError("expected either -, ( or numeral, but got " + lookahead);
		}

		return result;
	}

	Tree subexpression() throws SyntaxError{
		Tree result = new Tree("subexpression");

		if(lookahead.equals("+") || lookahead.equals("-")){
			System.out.println("deriving subexpression -> addoperator term subexpression");
			result.child(addoperator());
			result.child(term());
			result.child(subexpression());
		}else if(lookahead.equals(";")){
			System.out.println("deriving subexpression -> ");
		}else{
			throw new SyntaxError("expected either +, - or ;, but got " + lookahead);
		}

		return result;
	}

	Tree term() throws SyntaxError{	
		Tree result = new Tree("term");

		if(lookahead.equals("-") || lookahead.equals("(") || lookahead.equals("numeral")){
			System.out.println("deriving term -> factor subterm");
			result.child(factor());
			result.child(subterm());
		}else{
			throw new SyntaxError("expected either -, ( or numeral, but got " + lookahead);
		}

		return result;
	}

	Tree subterm() throws SyntaxError{
		Tree result = new Tree("subterm");

		if(lookahead.equals("*") || lookahead.equals("/") || lookahead.equals("%")){
			System.out.println("deriving subterm -> multoperator factor");
			result.child(multoperator());
			result.child(factor());
		}else if(lookahead.equals("+") || lookahead.equals("-")){
			System.out.println("deriving subterm -> ");
		}else{
			throw new SyntaxError("expected either +, -, *, / or %, but got " + lookahead);
		}

		return result;
	}

	Tree addoperator() throws SyntaxError{
		Tree result = new Tree("addoperator");

		if(lookahead.equals("+")){
			System.out.println("deriving addoperator -> +");
			result.child(terminal("+"));
		}else if(lookahead.equals("-")){
			System.out.println("deriving addoperator -> -");
			result.child(terminal("-"));
		}else{
			throw new SyntaxError("expected + or -, but got " + lookahead);
		}

		return result;
	}

	Tree multoperator() throws SyntaxError{
		Tree result = new Tree("multoperator");

		if(lookahead.equals("*")){
			System.out.println("deriving multoperator -> *");
			result.child(terminal("*"));
		}else if(lookahead.equals("/")){
			System.out.println("deriving multoperator -> /");
			result.child(terminal("/"));
		}else if(lookahead.equals("%")){
			System.out.println("deriving multoperator -> %");
			result.child(terminal("%"));
		}else{
			throw new SyntaxError("expected *, / or %, but got " + lookahead);
		}

		return result;
	}

	Tree factor() throws SyntaxError{
		Tree result = new Tree("factor");

		if(lookahead.equals("-")){
			System.out.println("deriving factor -> - factor");
			result.child(terminal("-"));
			result.child(factor());
		}else if(lookahead.equals("(")){
			System.out.println("deriving factor -> ( expression )");
			result.child(terminal("("));
			result.child(expression());
			result.child(terminal(")"));
		}else if(lookahead.equals("numeral")){
			System.out.println("deriving factor -> numeral");
			result.child(terminal("numeral"));
		}else{
			throw new SyntaxError("expected -, ( or numeral, but got " + lookahead);
		}
		return result;
	}

	Tree terminal(String t) throws SyntaxError{
		if(lookahead.equals(t)){
			System.out.println("matching " + t);
			nextToken();
			return new Tree(t);
		}else{
			throw new SyntaxError("expected " + t + ", but got " + lookahead);
		}
	}

	private void nextToken(){
		lookahead = tokenstream.more()? tokenstream.get():null(); 
	}



}
